package hbase.api;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: laoyu
 * @Date: 2020/6/7 11:12
 * @Description:
 */
public class TestHbase {
    //读取配置文件
    static Configuration conf = HBaseConfiguration.create();

    /**
     * 列出数据库中所有表
     */
    public static void list() throws IOException {
        //创建数据库连接
        Connection conn = ConnectionFactory.createConnection(conf);
        //Admin用于管理HBase数据库的信息
        Admin admin = conn.getAdmin();
        System.out.println("list table:");
        for (TableName name : admin.listTableNames()) {
            System.out.println(name);
            //关闭连接
            conn.close();
        }
    }


    /**
     * 删除表
     * 若表存在则删除
     *
     * @param tableName 表名
     * @throws IOException
     */
    public static void removeTable(String tableName) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Admin admin = conn.getAdmin();
        TableName tn = TableName.valueOf(tableName);
        //如果存在先删除
        if (admin.tableExists(tn)) {
            //先使表无效
            admin.disableTable(tn);
            admin.deleteTable(tn);
            System.out.println("表" + tableName + "已删除！");
        }
        conn.close();
    }

    /**
     * 创建表
     * 当需要创建的表存在时，删除后再创建，这只适合于测试使用，生产上需慎用
     *
     * @param tableName   表名
     * @param familyNames 列族
     * @throws IOException
     */
    public static void create(String tableName, String... familyNames) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Admin admin = conn.getAdmin();
        TableName tn = TableName.valueOf(tableName);
        //如果存在先删除
        if (admin.tableExists(tn)) {
            //先使表无效
            admin.disableTable(tn);
            admin.deleteTable(tn);
        }

//        //HTableDescriptor包含了表的名字及其对应的列族
//        HTableDescriptor htd = new HTableDescriptor(tn);
//        for (String family : familyNames) {
//            htd.addFamily(new HColumnDescriptor(family));
//        }
//        admin.createTable(htd);

        //创建集合用于存放ColumnFamilyDescriptor对象
        List<ColumnFamilyDescriptor> families = new ArrayList<ColumnFamilyDescriptor>();
        //将每个familyName对应的ColumnFamilyDescriptor对象添加到families集合中保存
        for (String family : familyNames) {
            families.add(ColumnFamilyDescriptorBuilder.newBuilder(family.getBytes()).build());
        }

        // 构建TableDescriptor对象，以保存tableName与familyNames
        TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tn)
                .setColumnFamilies(families).build();

        // 有了表描述器便可以创建表了
        admin.createTable(tableDescriptor);

        conn.close();
        System.out.println("表创建成功！");
    }


    /**
     * 查看表结构
     *
     * @param tableName
     * @throws IOException
     */
    public static void describe(String tableName) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Admin admin = conn.getAdmin();

        TableName tn = TableName.valueOf(tableName);
//        HTableDescriptor htd = admin.getTableDescriptor(tn);
//        System.out.println("========" + tableName + "的表结构如下：=========");
//        for (HColumnDescriptor hcd : htd.getColumnFamilies()) {
//            System.out.println(hcd.getNameAsString());
//        }

        // 通过表名获取ColumnFamilyDescriptors，注意返回的是数组
        ColumnFamilyDescriptor[] families = admin.getDescriptor(tn).getColumnFamilies();
        for (ColumnFamilyDescriptor family : families) {
            System.out.println(family.getNameAsString());
            System.out.println(family.getBlocksize());
            System.out.println(family.getMaxVersions());
            System.out.println(family.getEncryptionType());
            System.out.println(family.getTimeToLive());
            System.out.println(family.getDFSReplication() + "\n");
        }
        System.out.println("===================================");
        conn.close();
    }

    /**
     * 修改表——增加列族
     *
     * @param tableName
     * @param familyNames
     * @throws IOException
     */
    public static void addColumnFamily(String tableName, String... familyNames) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Admin admin = conn.getAdmin();

        TableName tn = TableName.valueOf(tableName);

//        HTableDescriptor htd = admin.getTableDescriptor(tn);
//        for (String family : familyNames) {
//            htd.addFamily(new HColumnDescriptor(family));
//        }
//
//        admin.modifyTable(tn, htd);

        // 通过新增的familyName来构建ColumnFamilyDescriptor对象
        ColumnFamilyDescriptor descriptor = null;
        for (String family : familyNames) {
            descriptor = ColumnFamilyDescriptorBuilder.newBuilder(family.getBytes()).build();
            admin.addColumnFamily(tn, descriptor);
        }
        conn.close();
        System.out.println("表结构修改完成！");
    }

    /**
     * 修改表——删减列族
     *
     * @param tableName
     * @param familyNames
     * @throws IOException
     */
    public static void removeColumnFamily(String tableName, String... familyNames) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Admin admin = conn.getAdmin();
        TableName tn = TableName.valueOf(tableName);

        for (String family : familyNames) {
            if (family != null) {
                admin.deleteColumnFamily(tn, Bytes.toBytes(family));
                System.out.println("列族" + family + "已删除！");
            }
        }
        conn.close();
    }


    /**
     * 向表中插入数据
     *
     * @throws IOException
     */
    public static void putData(String tableName) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Table tb = conn.getTable(TableName.valueOf(tableName));

        Put p = new Put(Bytes.toBytes("jason"));
        p.addColumn(Bytes.toBytes("grade"), Bytes.toBytes(""), Bytes.toBytes("2"));
        p.addColumn(Bytes.toBytes("course"), Bytes.toBytes("math"), Bytes.toBytes("57"));
        p.addColumn(Bytes.toBytes("course"), Bytes.toBytes("art"), Bytes.toBytes("87"));
        tb.put(p);

        p = new Put(Bytes.toBytes("tom"));
        p.addColumn(Bytes.toBytes("grade"), Bytes.toBytes(""), Bytes.toBytes("1"));
        p.addColumn(Bytes.toBytes("course"), Bytes.toBytes("math"), Bytes.toBytes("89"));
        p.addColumn(Bytes.toBytes("course"), Bytes.toBytes("art"), Bytes.toBytes("80"));
        tb.put(p);

        conn.close();

    }


    /**
     * 按行键获取
     *
     * @param tableName
     * @param rowKey
     * @throws IOException
     */
    public static void get(String tableName, String rowKey) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Table tb = conn.getTable(TableName.valueOf(tableName));

        Get g = new Get(Bytes.toBytes(rowKey));
        Result result = tb.get(g);

        System.out.println(String.format("result.value=%s,result.toString:%s"
                , Bytes.toString(result.value()), result));

        conn.close();
    }


    /**
     * 按行键、列值获取
     *
     * @param tableName
     * @param rowKey
     * @param family
     * @throws IOException
     */
    public static void get(String tableName, String rowKey, String family) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Table tb = conn.getTable(TableName.valueOf(tableName));

        Get g = new Get(Bytes.toBytes(rowKey));
        g.addFamily(Bytes.toBytes(family));

        Result result = tb.get(g);

        System.out.println(String.format("result.value=%s,result.toString:%s"
                , Bytes.toString(result.value()), result));

        conn.close();

    }

    /**
     * 按行键、列值、修饰符获取
     *
     * @param tableName
     * @param rowKey
     * @param family
     * @param qualifier
     * @throws IOException
     */
    public static void get(String tableName, String rowKey, String family, String qualifier) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Table tb = conn.getTable(TableName.valueOf(tableName));

        Get g = new Get(Bytes.toBytes(rowKey));
        g.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));

        Result result = tb.get(g);

        System.out.println(String.format("result.value=%s,result.toString:%s"
                , Bytes.toString(result.value()), result));

        conn.close();

    }


    /**
     * 全表扫描
     *
     * @param tableName
     * @throws IOException
     */
    public static void scan(String tableName) throws IOException {
        Connection conn = ConnectionFactory.createConnection(conf);
        Table tb = conn.getTable(TableName.valueOf(tableName));

        //全表扫描
        ResultScanner scanner = tb.getScanner(new Scan());

        for (Result row : scanner) {
            System.out.println(row);

            for (Cell cell : row.listCells()) {
                System.out.println("RowKey:" + Bytes.toString(row.getRow())
                        + " Family:" + Bytes.toString(CellUtil.cloneFamily(cell))
                        + " Qualifier:" + Bytes.toString(CellUtil.cloneQualifier(cell))
                        + " Value:" + Bytes.toString(CellUtil.cloneValue(cell)));
            }
        }
        conn.close();
    }


    public static void main(String[] args) throws IOException {
//        create("scores","grade","course");
//        describe("scores");

//        addColumnFamily("scores", "n1", "n2");
//        describe("scores");

//        removeColumnFamily("scores","n1","n2");
//        describe("scores");

//        putData("scores");

//        get("scores", "jason");
//        get("scores", "jason", "grade");
//        get("scores", "jason", "course", "math");

        scan("scores");
    }

}
